#include <ne.h>
#include <system/GlutApplication.h>
using namespace ne;
using namespace std;

GlutApplication *pApplication;
SkeletonPtr skeleton;

bool convertSkeleton(const string &inFile)
{
    FILE *skeletonFile = fopen(inFile.c_str(), "r");
    if (!skeletonFile)
    {
        cerr << "Error: Can't find Skeleton file [" << inFile << "]\n";
        return false;
    }

    Engine *pEngine = Engine::GetSingletonPtr();
    SkeletonManager *pSkeletonManager = pEngine->getSkeletonManager();
    char str[MAX_STRING_LENGTH_IN_MESH_FILE];

    fscanf(skeletonFile, "Name = %s\n", str);
    printf("Name = %s\n", str);

    string outFile = str;
    outFile += ".skeleton";

    SkeletonPtr pSkeleton = pSkeletonManager->create(str, outFile, true);

    int numJoints = 0;
    fscanf(skeletonFile, "NumJoints = %d\n", &numJoints);
    printf("NumJoints = %d\n", numJoints);

    vector<ne::uint16_t> handleList(numJoints);
    vector<ne::uint16_t> parentList(numJoints);

    for (int i=0; i<numJoints; ++i)
    {
        ne::uint16_t handle = 0;
        fscanf(skeletonFile, "Handle = %hu\n", &handle);
        printf("Handle = %hu\n", handle);
        handleList[i] = handle;

        ne::uint16_t parent = Joint::JOINT_NO_PARENT_HANDLE;
        fscanf(skeletonFile, "Parent = %hu\n", &parent);
        printf("Parent = %hu\n", parent);
        parentList[i] = parent;

        fscanf(skeletonFile, "Name = %s\n", str);
        printf("Name = %s\n", str);
        printf("Convert Joint [%s] ... ...\n", str);

        Joint *pJoint = pSkeleton->createJoint(handle, str);
        if (pJoint)
        {
            Vector3 position(Vector3::ZERO);
            fscanf(skeletonFile, "Position = %f %f %f\n", &position.x, &position.y, &position.z);
            pJoint->setPosition(position);

            Quaternion oritation(Quaternion::ZERO);
            fscanf(skeletonFile, "Oritation = %f %f %f %f\n", &oritation.x, &oritation.y, &oritation.z, &oritation.w);
            pJoint->setOrientation(oritation);

            Vector3 scale(Vector3::ONE);
            fscanf(skeletonFile, "Scale = %f %f %f\n", &scale.x, &scale.y, &scale.z);
            pJoint->setScale(scale);

            printf("%hu\n", pJoint->getHandle());
            printf("[Ok]\n");
        }
    }

    for (int i=0; i<numJoints; ++i)
    {
        Joint *pJoint = pSkeleton->getJoint(handleList[i]);
        Joint *pParent = pSkeleton->getJoint(parentList[i]);
        if (pJoint && pParent)
        {
            pParent->addChild(pJoint);
        }
    }

    pSkeleton->setBinding();
    pSkeleton->deriveRootJoint();
    pSkeleton->download();
    printf("========== Finished Skeleton convert\n");
    fclose(skeletonFile);
    skeleton = pSkeleton;
    return true;
}

bool convertAnimation(const string &inFile)
{
    FILE *animationFile = fopen(inFile.c_str(), "r");
    if (!animationFile)
    {
        cerr << "Error: Can't find Animation file [" << inFile << "]\n";
        return false;
    }

    Engine *pEngine = Engine::GetSingletonPtr();
    AnimationManager *pAnimationManager = pEngine->getAnimationManager();
    char str[MAX_STRING_LENGTH_IN_MESH_FILE];

    fscanf(animationFile, "Name = %s\n", str);
    printf("Name = %s\n", str);

    string outFile = str;

    AnimationGroupPtr pAnimationGroup = pAnimationManager->create(str, outFile + ".animationGroup", true);
    AnimationPtr pAnimation = pAnimationGroup->create(str, outFile + ".animation", true);

    ne::real length = 0.0f;
    fscanf(animationFile, "Length = %f\n", &length);
    printf("Length = %f\n", length);
    pAnimation->setLength(length);

    int numNodeTracks = 0;
    fscanf(animationFile, "NumNodeTracks = %d\n", &numNodeTracks);
    printf("NumNodeTracks = %d\n", numNodeTracks);

    for (int i=0; i<numNodeTracks; ++i)
    {
        ne::uint16_t handle = 0;
        fscanf(animationFile, "Handle = %hu\n", &handle);
        printf("Handle = %hu\n", handle);

        NodeAnimationTrackPtr pTrack = pAnimation->createNodeTrack(handle);
        Joint *pJoint = skeleton->getJoint(handle);

        int numKeyFrames = 0;
        fscanf(animationFile, "NumKeyFrames = %d\n", &numKeyFrames);

        for (int j=0; j<numKeyFrames; ++j)
        {
            ne::real time = 0.0f;
            fscanf(animationFile, "Time = %f\n", &time);

            TransformKeyFrame *pKeyFrame = pTrack->createTransformKeyFrame(time);
            Vector3 position(Vector3::ZERO);
            fscanf(animationFile, "Position = %f %f %f\n", &position.x, &position.y, &position.z);
            pKeyFrame->setTranslate(pJoint->getInitialPosition() - position);

            Quaternion oritation(Quaternion::ZERO);
            fscanf(animationFile, "Oritation = %f %f %f %f\n", &oritation.x, &oritation.y, &oritation.z, &oritation.w);
            Quaternion rotate = pJoint->getInitialOrientation().getRotationRelative(oritation);
            pKeyFrame->setRotate(rotate);

            Vector3 scale(Vector3::ONE);
            fscanf(animationFile, "Scale = %f %f %f\n", &scale.x, &scale.y, &scale.z);
            pKeyFrame->setScale(pJoint->getInitialScale() / scale);
        }
    }

    pAnimation->download();
    pAnimationGroup->download();

    printf("========== Finished Aniamtion convert\n");
    fclose(animationFile);
    return true;
}

int main(int argc, char *argv[])
{
    pApplication = new ne::GlutApplication();

    if (argc > 1)
    {
        if (convertSkeleton(argv[1]))
        {
            if (argc > 2)
            {
                convertAnimation(argv[2]);
            }
        }
    }

    return 0;
}
